package com.mgee.netty.server.netty;

import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import com.alibaba.fastjson.JSON;
import com.mgee.netty.server.pojo.NewChatUserInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.util.JsonFormat.TypeRegistry;
import com.mgee.netty.server.pojo.ChatUserInfo;
import com.mgee.netty.server.pojo.LobbyInfo;
import com.mgee.netty.server.pojo.LobbyRoomInfo;
import com.mgee.netty.server.protobuf.ImProto;
import com.mgee.netty.server.protobuf.ImProto.LoginResponse;
import com.mgee.netty.server.protobuf.ImProto.UserloginRsp;
import com.mgee.netty.server.service.LobbyRoomService;
import com.mgee.netty.server.service.LobbyService;
import com.mgee.netty.server.service.RoomService;
import com.mgee.netty.server.util.ChannelUtils;
import com.mgee.netty.server.util.DateUtil;

import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;

/**
 * 用户通讯管理工具
 * @author mileswan
 *
 */
@Slf4j
@Component
public class SessionManager {

	public static String TABLE_ROTATE_KEY = "table_rotate_key";
	public static String CUBE_ROTATE_KEY = "cube_rotate_key";

	/** 缓存用户id与对应的会话 */
	public static ConcurrentMap<String, IoSession> userId2Sessions = new ConcurrentHashMap<>();
	
	/** 缓存漫游房间id与对应的用户信息 */
	public static ConcurrentMap<String, Map<String, ChatUserInfo>> groupId2Users = new ConcurrentHashMap<>();
	// roomNo为key
	public static ConcurrentMap<String, Map<String, NewChatUserInfo>> newGroupId2Users = new ConcurrentHashMap<>();

	/** 缓存对应的用户id与聊天群组id */
	public static ConcurrentMap<String, String> userId2GroupIds = new ConcurrentHashMap<>();
	
	/** 缓存用户是否已经登陆验证 */
	private static ConcurrentMap<String, Boolean> userId2Islogin = new ConcurrentHashMap<>();
	
	
	/*-------------------- 以下是民航Demo项目新加的 -----------------------*/
	/** 缓存大厅信息 */
	public static ConcurrentMap<String, LobbyInfo> lobbies = new ConcurrentHashMap<>();
	
	/** 缓存用户大厅信息 */
	public static ConcurrentMap<String, LobbyInfo> userId2Lobbies = new ConcurrentHashMap<>();
	
	/** 缓存对应的用户id与聊天群组id */
	public static ConcurrentMap<String, LobbyRoomInfo> userId2LobbyRooms = new ConcurrentHashMap<>();

	public static ConcurrentMap<String, Integer> turnTableRotateCache = new ConcurrentHashMap<>();

	public static ConcurrentMap<String, Integer> cubeRotateCache = new ConcurrentHashMap<>();


	/** 缓存大厅用户信息 */
	public static ConcurrentMap<String, Map<String, ChatUserInfo>> lobby2Users = new ConcurrentHashMap<>();
	
	/** 缓存演练房间id与对应的用户信息 */
	public static ConcurrentMap<String, Map<String, ChatUserInfo>> lobbyRoomId2Users = new ConcurrentHashMap<>();

	public static List<Integer> moveSubIdList = Collections.synchronizedList(new ArrayList<>());
	
	public static TypeRegistry typeRegistry = JsonFormat.TypeRegistry.newBuilder()
			.add(LoginResponse.getDescriptor())
			.add(UserloginRsp.getDescriptor())
			.build();
	
	@Autowired
	private RoomService roomService;
	@Autowired
	private LobbyService lobbyService;
	@Autowired
	private LobbyRoomService lobbyRoomService;
 
	/**
	 * 返回用户是否已经登陆状态
	 * @param userId
	 * @return
	 */
	public boolean isUserLogin(String userId) {
		return userId2Islogin.getOrDefault(userId, false);
	}
	/**
	 * 设置用户登录状态的缓存
	 * @param userId
	 * @param isSuccess
	 * @return
	 */
	public void setUserLogin(String userId, boolean isSuccess) {
		if(isSuccess != true) {
			userId2Islogin.remove(userId);
		}else {
			userId2Islogin.put(userId, isSuccess);
		}
	}
	/**
	 * 向指定用户id发送消息
	 * @param msg
	 * @param userId
	 */
	public void sendMessageTo(ImProto.ImMsg msg,String userId){
		if(msg == null || StringUtils.isEmpty(userId)) return;
 
		IoSession session = userId2Sessions.get(userId);
		if (session != null) {
			session.sendMessage(msg);
		}
	}
 
	/**
	 *  向所有在线用户发送数据包
	 */
	public void sendMessageToAllUsers(ImProto.ImMsg msg){
		//TODO 如果是分布式则还需要修改
		if(msg == null ) return;
 
		userId2Sessions.values().forEach( (session) -> session.sendMessage(msg));
	}
	
	/**
	 *  向用户所在大厅内的所有在线用户发送数据包
	 */
	public void sendMessageToLobbyUsers(ImProto.ImMsg msg, String sender_uid, boolean includeSelf){
		if(msg == null || userId2Lobbies.get(sender_uid) == null) return;
		
		String lobbyName = userId2Lobbies.get(sender_uid).getName();
		
		Iterator<Entry<String, ChatUserInfo>> iterator = lobby2Users.get(lobbyName).entrySet().iterator();
		while(iterator.hasNext()) {
			Map.Entry<String, ChatUserInfo> entry = (Map.Entry<String, ChatUserInfo>)iterator.next();
			ChatUserInfo user = entry.getValue();
			if(sender_uid.equals(user.getUid()) && !includeSelf) {
				continue;
			}
			if(userId2Sessions.get(user.getUid()) == null) {
				userId2Sessions.remove(user.getUid());
				continue;
			}
			userId2Sessions.get(user.getUid()).sendMessage(msg);
		}
	}
	public void sendMessageToLobbyUsers(ImProto.ImMsg msg, String sender_uid){
		sendMessageToLobbyUsers(msg, sender_uid, false);
	}
	public void sendMessageToAllLobbyUsers(ImProto.ImMsg msg, String sender_uid){
		sendMessageToLobbyUsers(msg, sender_uid, true);
	}
	
	/**
	 *  向用户所在房间的所有在线用户发送数据包(改过了，新的)
	 */
	public void sendMessageToRoomUsers(ImProto.ImMsg msg, String sender_uid, boolean includeSelf){
		log.info("SessionManager sendMessageToRoomUsers includeSelf:{}, sender_uid is:{}", includeSelf, sender_uid);

		if(msg == null) return;
		
		String room_id = userId2GroupIds.get(sender_uid);
		log.info("SessionManager sendMessageToRoomUsers room_id is:{}", room_id);
		if(room_id == null || newGroupId2Users.get(room_id) == null) return;
		log.info("SessionManager sendMessageToRoomUsers newGroupId2Users:{}", String.valueOf(newGroupId2Users));
		Iterator<Entry<String, NewChatUserInfo>> iterator = newGroupId2Users.get(room_id).entrySet().iterator();
		while(iterator.hasNext()) {
			Map.Entry<String, NewChatUserInfo> entry = (Map.Entry<String, NewChatUserInfo>)iterator.next();
			NewChatUserInfo user = entry.getValue();
			log.info("SessionManager sendMessageToRoomUsers user:{}", JSON.toJSONString(user));
			if(sender_uid.equals(user.getUid()) && !includeSelf) {
				continue;
			}
			if(userId2Sessions.get(user.getUid()) == null) {
				userId2Sessions.remove(user.getUid());
				continue;
			}
			log.info("SessionManager sendMessageToRoomUsers user.getUid() is:{}", user.getUid());

			userId2Sessions.get(user.getUid()).sendMessage(msg);
		}
	}
	public void sendMessageToRoomUsers(ImProto.ImMsg msg, String sender_uid){
		sendMessageToRoomUsers(msg, sender_uid, false);
	}
	// 所有人包含自己
	public void sendMessageToAllRoomUsers(ImProto.ImMsg msg, String sender_uid){
		sendMessageToRoomUsers(msg, sender_uid, true);
	}
	
	/**
	 *  向用户所在大厅房间的所有在线用户发送数据包
	 */
	public void sendMessageToLobbyRoomUsers(ImProto.ImMsg msg, String sender_uid, boolean includeSelf){
		if(msg == null || userId2LobbyRooms.get(sender_uid) == null) return;
		
		String room_id = userId2LobbyRooms.get(sender_uid).getName();
		if(room_id == null || lobbyRoomId2Users.get(room_id) == null) return;
		
		Iterator<Entry<String, ChatUserInfo>> iterator = lobbyRoomId2Users.get(room_id).entrySet().iterator();
		while(iterator.hasNext()) {
			Map.Entry<String, ChatUserInfo> entry = (Map.Entry<String, ChatUserInfo>)iterator.next();
			ChatUserInfo user = entry.getValue();
			if(sender_uid.equals(user.getUid()) && !includeSelf) {
				continue;
			}
			if(userId2Sessions.get(user.getUid()) == null) {
				userId2Sessions.remove(user.getUid());
				continue;
			}
			userId2Sessions.get(user.getUid()).sendMessage(msg);
		}
	}
	public void sendMessageToLobbyRoomUsers(ImProto.ImMsg msg, String sender_uid){
		sendMessageToLobbyRoomUsers(msg, sender_uid, false);
	}
	public void sendMessageToAllLobbyRoomUsers(ImProto.ImMsg msg, String sender_uid){
		sendMessageToLobbyRoomUsers(msg, sender_uid, true);
	}
	
	/**
	 * 发送给演练房间的其他已创建人物的玩家
	 * @param msg
	 * @param sender_uid
	 * @param includeSelf
	 */
	public void sendMessageToLobbyRoomPlayers(ImProto.ImMsg msg, String sender_uid, boolean includeSelf){
		if(msg == null || userId2LobbyRooms.get(sender_uid) == null) return;
		
		String room_id = userId2LobbyRooms.get(sender_uid).getName();
		if(room_id == null || lobbyRoomId2Users.get(room_id) == null) return;
		
		Iterator<Entry<String, ChatUserInfo>> iterator = lobbyRoomId2Users.get(room_id).entrySet().iterator();
		while(iterator.hasNext()) {
			Map.Entry<String, ChatUserInfo> entry = (Map.Entry<String, ChatUserInfo>)iterator.next();
			ChatUserInfo user = entry.getValue();
			if(sender_uid.equals(user.getUid()) && !includeSelf) {
				continue;
			}
			
			IoSession userSession = userId2Sessions.get(user.getUid());
			if(userSession == null) {
				userId2Sessions.remove(user.getUid());
				continue;
			}
			
			if(user.getLobbyRoomPlayerPack() == null) {
				continue;
			}
			
			userSession.sendMessage(msg);
		}
	}
	
	
 
	public IoSession getSessionBy(String userId) {
		return userId2Sessions.get(userId);
	}
	
	public boolean isUserRegistered(String userId) {
		return userId2Sessions.containsKey(userId);
	}
 
	public boolean registerSession(ChatUserInfo user, IoSession session) {
 
		if(null == user || StringUtils.isEmpty(user.getUid())) {
			return false;
		}
		if(userId2Sessions.containsKey(user.getUid())) {
			if(session.equals(userId2Sessions.get(user.getUid()))) {
				log.info("[{}] 已经登录...", user.getUid());
				//return true;
			}else if(userId2Sessions.get(user.getUid()).getClientDisconnectTime() != null) {// 已存在的session是已断开延迟等待关闭中
				userId2Sessions.get(user.getUid()).setClientDisconnectTime(null);
			}
			else {
				return false;
			}
		}
		
		session.setUser(user);
		userId2Sessions.put(user.getUid(), session);
		log.info("[{}] 登录成功...", user.getUid());
        
		return true;
	}

	public boolean newRegisterSession(NewChatUserInfo user, IoSession session) {

		if(null == user || StringUtils.isEmpty(user.getUid())) {
			return false;
		}
		if(userId2Sessions.containsKey(user.getUid())) {
			if(session.equals(userId2Sessions.get(user.getUid()))) {
				log.info("[{}] 已经登录...", user.getUid());
				//return true;
			} else {
//				return false; // todo 先注释吧
			}
		}

		session.setNewChatUserInfo(user);
		userId2Sessions.put(user.getUid(), session);
		log.info("[{}] 预留用户session成功...", user.getUid());

		return true;
	}
 
	/**
	 *   注销用户通信渠道
	 */
	public void unregisterUserContext(IoSession session){
		
		ChatUserInfo sessionUser = session.getUser();
		if(sessionUser != null) {
			String userId = sessionUser.getUid();
			
			if(userId2Sessions.get(userId) != null && userId.equals(userId2Sessions.get(userId).getUser().getUid())) {
				
				String roomId = userId2GroupIds.get(userId);
				
				if(StringUtils.isNotBlank(roomId)) {
					
					roomService.processExitRoom(userId, roomId);
				}
				
				LobbyRoomInfo lobbyRoomInfo = SessionManager.userId2LobbyRooms.get(userId);
				if(lobbyRoomInfo != null) {
					lobbyRoomService.processLeaveRoom(sessionUser, lobbyRoomInfo);
				}
				
				LobbyInfo lobbyInfo = SessionManager.userId2Lobbies.get(userId);
				if(lobbyInfo != null) {
					lobbyService.processExitLobby(userId, lobbyInfo);
				}
				
				userId2Lobbies.remove(userId);
				userId2LobbyRooms.remove(userId);
				userId2Sessions.remove(userId);
				userId2Islogin.remove(userId);
				userId2GroupIds.remove(userId);
				// 计算登录用户累计在线时间
			}
			//调用登出接口
			
			// 记录登出历史
		}
		if (session != null) {
			session.close();
		}
	}
	
	public void unregisterUserContext(Channel context){
		if(context  == null){
			return;
		}
		IoSession session = ChannelUtils.getSessionBy(context);
		unregisterUserContext(session);
	}
	
	/**
	 * 延迟注销
	 * @param context
	 * @param delaySeconds
	 */
	public void disconnectAndDelayUnregister(Channel context, int delaySeconds){
		if(context  == null){
			return;
		}
		IoSession session = ChannelUtils.getSessionBy(context);
		if(session == null || session.getUser() == null || !userId2Sessions.containsKey(session.getUser().getUid())) {
			session = null;
			return;
		}
		session.setClientDisconnectTime(DateUtil.now());
		
		Timer timer = new Timer(); 
		IoSession timerSession = session;
		
		timer.schedule(new TimerTask() {
		  
		  @Override public void run() { 
			  log.info("Detect delayed unregister user " + timerSession.getUser().getUid()); 
			  Date clientDisconnectTime = timerSession.getClientDisconnectTime();
			  if(null == clientDisconnectTime) { 
				  timer.cancel(); 
			  }else if(DateUtil.getSecondsValue(clientDisconnectTime) > delaySeconds) { // 超过delaySeconds秒还未登录则断开session 
				  unregisterUserContext(timerSession);
				  timer.cancel(); 
			  }
		  }},  0,1000);
		
	}

	// 添加moveSubId
	public void addMoveSubIdList(Integer subId){
		if(moveSubIdList.contains(subId)){
			return;
		}
		moveSubIdList.add(subId);
	}

	// 移除moveSubId
	public void removeMoveSubId(Integer subId){
		moveSubIdList.remove(subId);
	}

	// 清空，就是复原魔方
	public void cleanMoveSubIdList() {
		moveSubIdList.clear();
	}

	// 盘子旋转角度
	public void setTurnTableRotateWork(Integer rotate){
		turnTableRotateCache.put(TABLE_ROTATE_KEY, rotate);
	}

	public Integer getTurnTableRotateWork(){
		return Objects.isNull(turnTableRotateCache.get(TABLE_ROTATE_KEY)) ? 0 : turnTableRotateCache.get(TABLE_ROTATE_KEY);
	}

	// 盘子旋转角度
	public void setCubeRotateWork(Integer rotate){
		cubeRotateCache.put(CUBE_ROTATE_KEY, rotate);
	}

	public Integer getCubeRotateWork(){
		return Objects.isNull(cubeRotateCache.get(CUBE_ROTATE_KEY)) ? 0 : cubeRotateCache.get(CUBE_ROTATE_KEY);
	}



}
